from datetime import time, timedelta
import datetime
from typing import List
import rtdata

from common import str_to_market
from x_com import source_api


class CodeHolder:

    def __init__(self) -> None:
        '''
        value 类型:
        {
          market # 市场, 
          code: # 代码, 
          trading_code: # 交易代码, 
          name:  # 名字, 
          short_en: # 缩写, 
          listed_date: # 上市日期, 
          de_listed_date: # 退市日期, 
          trading_hours: # 交易时间段 , 
          contract_multiple: # 合约乘数, 
          min_tick: # 最小变动单位,
        }

        '''
        self.code_dict = {}
        self.min_time_scope_dict = {}

    def load(self, data_path: str) -> None:
        # 读取代码表文件
        code_list = rtdata.load_code_list(
            f"{data_path}/basic_data/code_list.z")
        for code_info in code_list:
            order_book_id = f"{code_info.market}.{code_info.code}"
            new_code_info = source_api.CodeInfo()
            new_code_info.market = str_to_market(code_info.market)
            new_code_info.code = code_info.code
            new_code_info.trading_code = code_info.trading_code
            new_code_info.name = code_info.name
            new_code_info.short_en = code_info.short_en
            new_code_info.listed_date = code_info.listed_date
            new_code_info.de_listed_date = code_info.de_listed_date
            new_code_info.trading_hours = code_info.trading_hours
            new_code_info.contract_multiple = code_info.contract_multiple
            new_code_info.min_tick = code_info.min_tick
            self.code_dict[order_book_id] = new_code_info
            
    # fre_num 为频率  1分钟则写 1，5 分钟 则写 5 ，依次类推
    #  本函数目标计算出,每一个标的的交易时间轴,比如 1 分钟:
    # [931, 932, 93,..., 1500]
    #  5 分钟频率:
    # [935, 940, 945,..., 1500]
    # 10 分钟频率
    # [940, 950, 1000,..., 1500]
    def get_min_time_scope(self, order_book_id, date: int, fre_num: int) -> List[int]:
        # 设置标的的 key，用于取缓存，
        key = f"{order_book_id}-{date}-{fre_num}"
        # 如果已经计算过，则从缓存中取出来
        time_scope = self.min_time_scope_dict.get(key)
        if time_scope is not None:
            return time_scope
        # 从代码表中获取标的的信息
        code_info = self.code_dict.get(order_book_id)
        if code_info is None:
            return []
        # 获取标的的时间段,格式为:[931, 1130, 1301, 1500]
        trading_hours_len = len(code_info.trading_hours)
        # 时间段为偶数,如果不是偶数,则说明数据出错,直接返回空数组即可
        if trading_hours_len % 2 != 0:
            return []
        # 时间轴数组
        time_scope = []
        # 传进来的日志格式为: 20241105
        # 必须转换为: 20241105000000000 
        real_date = date * 1_00_00_00_000

        # 构建一个虚拟日期,因为 datetime 操纵时间, 必须要有一个日期,这个日期随便填写一个即可
        virtual_date = datetime.date(2024, 1, 1)
        # 时间交易时间点,是成对出现的, 因此 步长 为 2
        for i in range(0, trading_hours_len, 2):
            # 获取时间段的开始时间
            start_time_int = code_info.trading_hours[i]
            # 获取时间段的结束时间
            end_time_int = code_info.trading_hours[i + 1]
            # 转换为 time
            start_time = time(hour=start_time_int // 100, minute=start_time_int % 100)
            end_time = time(hour=end_time_int // 100, minute=end_time_int % 100)
            # 转换为 datetime 格式
            start_datetime = datetime.datetime.combine(virtual_date, start_time)
            end_datetime = datetime.datetime.combine(virtual_date, end_time)
            # 因为默认的交易时间段, 开始时间都是加了 1 分钟的,因此要计算其他频率的时候,要先减去 1 分钟, 
            # 获取原始的开始时间点
            start_datetime -= timedelta(minutes=1)
            # 然后加上对应频率的时间, 计算出对应频率的开始四件点
            start_datetime += timedelta(minutes=fre_num)

            # 开始遍历    
            # 举例: start_datetime 开始时间为: 20240101 093100000
            current_time = start_datetime

            while current_time <= end_datetime:
              cur_min = real_date + current_time.hour * 1_00_00_000 + current_time.minute * 1_00_000
              time_scope.append(cur_min)
              # 加上频率获取对应的时间点 
              current_time += timedelta(minutes=fre_num)        
        self.min_time_scope_dict[key] = time_scope
        return time_scope
